package com.gframework.sqlparam;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.springframework.lang.Nullable;

import com.gframework.lang.ObjectRange;

/**
 * 简单的单表Sql操作条件封装类，本类实际上也是一个链表结构.
 * <p>
 * <strong>【警告】请勿让条件组互相引用形成循环引用，否则会出现问题！同时本类也是只可增不可减的</strong>
 * </p>
 * <p>
 * 每一个本类对象都是一个条件组，多个条件组可以使用 {@link #orNext(SqlParam)} 和 {@link #andNext(SqlParam)} 方法串联起来，类似于链表，他们之间的分隔符是由你连接时调用的方法决定的。<br>
 * </p>
 * <p>
 * 1、如果一个条件组对象的条件有A、B，另一个条件组的条件是C、D，两个条件组内部都是and连接，两个条件组则是or连接，那么最终生成的where条件是：
 * (A and B) or (C and D)
 * 
 * <pre>
 *  【例1】
 *  <code>
 *  SqlParam.and().eq("x","x").orNext(SqlParam.and().eq("y","y"))
 *  </code>
 *  【例1结果】
 *  (x = 'x') or (y = 'y')
 *  【例2】
 *  <code>
 *  SqlParam.and().eq("x","x").ne("z","z").orNext(SqlParam.and().eq("y","y"))
 *  </code>
 *  【例2结果】
 *  (x = 'x' and z != 'z') or (y = 'y')
 * </pre>
 * </p>
 * <p>
 * 2、整个SqlParam就是一个链表，在任意节点中执行 {@link #orNext(SqlParam)} 或 {@link #andNext(SqlParam)} 方法，都会在链表最后添加增加节点，而不会改变当前节点的next属性。
 * </p>
 * <pre>
 *  【例3】
 *  <code>
 *  SqlParam s1 = SqlParam.and().eq("x","x");
 *  SqlParam s2 = SqlParam.and().ne("y","y");
 *  s1.andNext(s2);
 *  s1.orNext(SqlParam.and().eq("z","z"))
 *  </code>
 *  【例3结果】
 *  (x = 'x') and (y != 'y') or (z = 'z')
 * </pre>
 * <p>
 * 3、如果你实例化了一个空的本类对象例如直接：SqlParam.and(); SqlParam.or();
 * 那么实际上是不会产生任何where条件的。
 * </p>
 * <p>
 * 本类是线程不安全的。
 * 同时本类支持序列化和RPC传输，但是请务必保证设置的value值也是可序列化的。
 * </p>
 * <ul>
 * <li><strong>[s]eq {@code -} </strong> {@code =} </li>
 * <li><strong>[s]ne {@code -} </strong> {@code !=} </li>
 * <li><strong>[s]in {@code -} </strong> {@code IN} </li>
 * <li><strong>[s]notIn {@code -} </strong> {@code NOT IN} </li>
 * <li><strong>[s]like {@code -} </strong> {@code LIKE} </li>
 * <li><strong>[s]isNull {@code -} </strong> {@code IS NULL} </li>
 * <li><strong>[s]isNotNull {@code -} </strong> {@code IS NOT NULL} </li>
 * <li><strong>[s]lt {@code -} </strong> {@code <} </li>
 * <li><strong>[s]le {@code -} </strong> {@code <=} </li>
 * <li><strong>[s]gt {@code -} </strong> {@code >} </li>
 * <li><strong>[s]ge {@code -} </strong> {@code >=} </li>
 * <li><strong>[s]between {@code -} </strong> {@code BETWEEN AND} </li>
 * <li><strong>orderBy {@code -} </strong> {@code ORDER BY} </li>
 * </ul>
 * 
 * @since 1.0.0
 * @author Ghwolf
 * 
 * @see ParamMode
 * @see SqlParamUtils
 */
public class SqlParam implements Serializable,SqlOperator,LambdaSqlParam {
	private static final long serialVersionUID = -4121781223761885869L;
	
	/**
	 * 当前条件组操作条件集合，条件连接使用的是 {@link #innerOp}
	 */
	private List<Param> params = new ArrayList<>(8);
	/**
	 * 下一个执行的条件组对象，和next的连接符号是next对象中的 {@link #outerOp} 属性
	 */
	private SqlParam next;
	
	/**
	 * 排序字段，仅查询时有用
	 */
	private String orderBy ;

	/**
	 * 当前条件组自己连接符，and或or
	 */
	private final String innerOp;
	/**
	 * 当前SqlParam对象和上一个sqlParam对象之间的关联符号，and或or
	 */
	private String outerOp;

	protected SqlParam(String innerOp) {
		this.innerOp = innerOp;
	}
	
	/**
	 * 用and连接符连接条件，解析对象属性中的{@link ParamMode}注解，并生成一个SqlParam类对象
	 * 
	 * @param obj 参数信息存放对象，只有包含了ParamMode注解的属性和方法才会被解析，可为null
	 * @return 返回SqlParam类对象，如果参数为null，则返回一个没有sql的SqlParam类对象
	 */
	public static SqlParam buildByParamModeAnd(@Nullable Object obj){
		return SqlParamUtils.paramModeAnd(obj);
	}
	/**
	 * 用or连接符连接条件，解析对象属性中的{@link ParamMode}注解，并生成一个SqlParam类对象
	 * 
	 * @param obj 参数信息存放对象，只有包含了ParamMode注解的属性和方法才会被解析，可为null
	 * @return 返回SqlParam类对象，如果参数为null，则返回一个没有sql的SqlParam类对象
	 */
	public static SqlParam buildByParamModeOr(Object obj){
		return SqlParamUtils.paramModeOr(obj);
	}
	
	/**
	 * 取得一个内部条件全是用and连接的条件组对象.
	 * 
	 * @return 返回内部条件连接符都是and的对象
	 */
	public static SqlParam and() {
		return new SqlParam(AND_STR);
	}

	/**
	 * 取得一个内部条件全是用or连接的条件组对象.
	 * 
	 * @return 返回内部条件连接符都是or的对象
	 */
	public static SqlParam or() {
		return new SqlParam(OR_STR);
	}

	/**
	 * 取得条件组集合链表，包括所有关联的条件组.
	 * <p>
	 * 链表的首个节点是当前节点，如果当前节点存在上个节点，则无法取得。
	 * 没有任何条件的条件组也不会存在在返回的链表中。
	 * </p>
	 * 
	 * @return 返回关联的条件组，如果没有则集合长度为0
	 */
	public List<SqlParam> getParamList() {
		List<SqlParam> list = new ArrayList<>();
		SqlParam sp = this;
		while (sp != null) {
			list.add(sp);
			sp = sp.next;
		}
		return list;
	}

	/**
	 * 和另外一个条件组建立and连接运算.
	 * <p>
	 * 如果已经连接了一个条件组，则会放到整个条件链表的最后面去
	 * </p>
	 * 
	 * @param sqlParam 要建立运算的另一个条件组，如果为null则什么都不做并返回null
	 * @return 返回当前对象
	 */
	public SqlParam andNext(@Nullable SqlParam sqlParam) {
		if (sqlParam != null) {
			if (this.next == null) {
				sqlParam.outerOp = AND_STR;
				this.next = sqlParam;
			} else {
				this.next.andNext(sqlParam);
			}
		}
		return this;
	}

	/**
	 * 和另外一个条件组建立or连接运算.
	 * <p>
	 * 如果已经连接了一个条件组，则会放到整个条件链表的最后面去
	 * </p>
	 * 
	 * @param sqlParam 要建立运算的另一个条件组，如果为null则什么都不做并返回null
	 * @return 返回当前对象
	 */
	public SqlParam orNext(SqlParam sqlParam) {
		if (sqlParam != null) {
			if (this.next == null) {
				sqlParam.outerOp = OR_STR;
				this.next = sqlParam;
			} else {
				this.next.andNext(sqlParam);
			}
		}
		return this;
	}
	
	/**
	 * 取得当前条件组的条件数量.
	 * <p>
	 * 如果要取得从当前节点开始的所有条件总数，可以调用{@link #getParamSize()}方法。
	 * </p>
	 * @return 返回条件数量，没有返回0
	 */
	public int getCurrentParamSize() {
		return this.params.size();
	}
	
	/**
	 * 取得从当前节点开始的所有条件数量.
	 * @return 返回从当前节点开始的全部条件数量，没有返回0
	 */
	public int getParamSize() {
		int size = 0 ;
		SqlParam sp = this ;
		while(sp != null) {
			size += sp.getCurrentParamSize();
			sp = sp.next;
		}
		return size ;
	}
	
	/**
	 * 取得where子句的sql语句（不含where，左右无括号），同时将其中包含的动态参数设置到params中.
	 * <p>此方法会生成基于mybatis类型的，采用自定义预编译参数名称的方式进行生成。
	 * <p>params可以为null，为null则不设置参数只生成sql语句。
	 * <p>如果无sql则返回null
	 * @param params 保存预编译参数的集合，可以为null
	 * @param 唯一的参数名称生成器
	 * @return 返回从当前节点一直向后递归生成的sql语句，如果无法生成sql即无where条件，则返回""
	 */
	public String getSql(@Nullable Map<String,Object> params,NameGenerator ng) {
		return getSql0(params,ng,MybatisParamStringWrapper.get());
	}
	/**
	 * 取得where子句的sql语句（不含where，左右无括号），同时将其中包含的动态参数设置到params中.
	 * <p>此方法会生成基于mybatis类型的，采用自定义预编译参数名称的方式进行生成。
	 * <p>params可以为null，为null则不设置参数只生成sql语句。
	 * <p>
	 * 如果无sql则返回null
	 * </p>
	 * @param params 保存预编译参数的集合，可以为null
	 * @return 返回从当前节点一直向后递归生成的sql语句，如果无法生成sql即无where条件，则返回""
	 */
	public String getSql(@Nullable Map<String,Object> params) {
		return this.getSql(params,new MybatisParamNameCacheGenerator());
	}
	/**
	 * 取得where子句的sql语句（不含where，左右无括号），同时将其中包含的动态参数设置到params中.
	 * <p>此方法会生成基于jdbc原生类型，预编译参数使用"?"进行填充的sql语句，并将参数按照顺序填充到params中。
	 * <p>params可以为null，为null则不设置参数只生成sql语句。
	 * <p>
	 * 如果无sql则返回null
	 * </p>
	 * @param params 保存预编译参数的集合，可以为null
	 * @return 返回从当前节点一直向后递归生成的sql语句，如果无法生成sql即无where条件，则返回""
	 */
	public String getSql(@Nullable List<Object> params) {
		return this.getSql0(params == null ? null : new ListParamMap(params),SqlMarkNameGenerator.build(),NonStringWrapper.get());
	}
	
	private String getSql0(@Nullable Map<String,Object> params,NameGenerator ng,StringWrapper stringWrapper) {
		if (ng == null) throw new NullPointerException("NameGenerator 不能为null！");
		
		StringBuilder sb = new StringBuilder();
		String sql = this.getCurrentSql(params, ng,stringWrapper);
		if (sql != null) {
			sb.append('(').append(sql).append(')');
		}
		SqlParam sp = this.next;
		while (sp != null) {
			sql = sp.getCurrentSql(params, ng,stringWrapper);
			if (sql != null) {
				sb.append(sp.outerOp).append('(').append(sql).append(')');
			}
			sp = sp.next;
		}
	
		return sb.length() == 0 ? "" : sb.toString();
	}
	
	/**
	 * 取得当前SqlParam节点的sql语句，不含左右括号
	 * @param param 设置参数的map集合，为null则不设置参数
	 * @param ng 参数绑定名称生成器
	 * @param stringWrapper 参数标记包装器
	 * @return 返回sql语句，没有返回""
	 */
	protected String getCurrentSql(Map<String,Object> param,NameGenerator ng,StringWrapper stringWrapper) {
		if (this.getParams().isEmpty()) return null ;
		
		StringBuilder sb = new StringBuilder();
		String op = this.innerOp;
		int foot = 0 ;
		int length = this.getParams().size() - 1;
		for (Param p : this.getParams()) {
			String w = p.getSql(param, ng,stringWrapper);
			if (w != null) {
				sb.append(w);
				if (foot ++ < length) {
					sb.append(op);
				}
			}
		}
		return sb.length() == 0 ? "" : sb.toString();
	}
	
	/**
	 * 添加一个等值判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param value 要进行比较的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam eq(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, EQ_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个不等判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param value 要进行比较的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam ne(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, NE_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam in(@Nullable String column, @Nullable Object[] values) {
		if (column == null || values == null || values.length == 0) return this;
		this.params.add(new Param(column, values, IN_STR, Param.INT_NOTIN));
		return this;
	}

	/**
	 * 添加一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam in(@Nullable String column, @Nullable Collection<?> values) {
		if (column == null || values == null || values.isEmpty()) return this;
		this.params.add(new Param(column, values, IN_STR, Param.INT_NOTIN));
		return this;
	}
	
	/**
	 * 添加一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，可以是数组，集合，或一个对象（会当做只有一个长度的集合处理），如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam in(@Nullable String column, @Nullable Object values) {
		if (column == null || values == null) return this;
		this.params.add(new Param(column, values, IN_STR, Param.INT_NOTIN));
		return this;
	}

	/**
	 * 添加一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam notIn(@Nullable String column, @Nullable Object[] values) {
		if (column == null || values == null || values.length == 0) return this;
		this.params.add(new Param(column, values, NI_STR, Param.INT_NOTIN));
		return this;
	}

	/**
	 * 添加一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam notIn(@Nullable String column, @Nullable Collection<?> values) {
		if (column == null || values == null || values.isEmpty()) return this;
		this.params.add(new Param(column, values, NI_STR, Param.INT_NOTIN));
		return this;
	}
	
	/**
	 * 添加一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，可以是数组，集合，或一个对象（会当做只有一个长度的集合处理），如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam notIn(@Nullable String column, @Nullable Object values) {
		if (column == null || values == null) return this;
		this.params.add(new Param(column, values, NI_STR, Param.INT_NOTIN));
		return this;
	}

	/**
	 * 添加一个LIKE判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值(%：匹配0个或多个值，_:匹配任意一个值)，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam like(@Nullable String column, @Nullable String value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, LIKE_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个NOT LIKE判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值(%：匹配0个或多个值，_:匹配任意一个值)，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam notLike(@Nullable String column, @Nullable String value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, NOT_LIKE_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个IS NULL判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam isNull(@Nullable String column) {
		if (column == null) return this;
		this.params.add(new Param(column, IS_NULL_STR, Param.SIMPLE_OPERATOR));
		return this;
	}

	/**
	 * 添加一个IS NOT NULL判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam isNotNull(@Nullable String column) {
		if (column == null) return this;
		this.params.add(new Param(column, IS_NOT_NULL_STR, Param.SIMPLE_OPERATOR));
		return this;
	}

	/**
	 * 添加一个小于{@code <}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam lt(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, LT_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个小于等于{@code <=}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam le(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, LE_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个大于{@code >}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam gt(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, GT_STR, Param.BINARY_OPERATOR));
		return this;
	}

	/**
	 * 添加一个大于等于{@code >=}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 */
	public SqlParam ge(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return this;
		this.params.add(new Param(column, value, GE_STR, Param.BINARY_OPERATOR));
		return this;
	}
	
	/**
	 * 添加一个BETWEEN AND判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param start 范围起始值，如果为null则什么都不做
	 * @param end 范围结束值，如果为null则什么都不做
	 * @return 返回当前调用对象
	 * @param <T> 泛型的目的保证start和end数据类型一致
	 */
	public <T extends Serializable> SqlParam betweenAnd(@Nullable String column, @Nullable T start, @Nullable T end) {
		if (column == null || start == null || end == null) return this;
		BetweenAndQuery<T> value = new BetweenAndQuery<>(start, end);
		this.params.add(new Param(column, value, null, Param.BETWEEN_AND));
		return this;
	}
	
	// lambda function

	@Override
	public SqlParam eq(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return eq(name,supplier.get());
	}

	@Override
	public SqlParam ne(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return ne(name,supplier.get());
	}

	@Override
	public SqlParam in(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		Object value = supplier.get();
		if (value == null) return this ;
		return in(name,value);
	}

	@Override
	public SqlParam notIn(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		Object value = supplier.get();
		if (value == null) return this ;
		return notIn(name,value);
	}

	@Override
	public SqlParam like(SerSupplier<String> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return like(name,supplier.get());
	}

	@Override
	public SqlParam notLike(SerSupplier<String> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return notLike(name,supplier.get());
	}

	@Override
	public SqlParam isNull(SerSupplier<Object> supplier) {
		return isNull(LambdaColumnNameUtil.getColumnName(supplier));
	}

	@Override
	public SqlParam isNotNull(SerSupplier<Object> supplier) {
		return isNotNull(LambdaColumnNameUtil.getColumnName(supplier));
	}

	@Override
	public SqlParam lt(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return lt(name,supplier.get());
	}

	@Override
	public SqlParam le(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return le(name,supplier.get());
	}

	@Override
	public SqlParam gt(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return gt(name,supplier.get());
	}

	@Override
	public SqlParam ge(SerSupplier<Object> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		return ge(name,supplier.get());
	}

	@Override
	public <T extends Serializable> SqlParam betweenAnd(SerSupplier<ObjectRange<T>> supplier) {
		String name = LambdaColumnNameUtil.getColumnName(supplier);
		ObjectRange<T> range = supplier.get();
		if (range == null) {
			return this ;
		}
		return betweenAnd(name,range.getStart(),range.getEnd());
	}
	
	// static get Param
	
	/**
	 * 获取一个等值判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param value 要进行比较的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param seq(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, EQ_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个不等判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param value 要进行比较的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sne(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, NE_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sin(@Nullable String column, @Nullable Object[] values) {
		if (column == null || values == null || values.length == 0) return null;
		return new Param(column, values, IN_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，可以是数组，集合，或一个对象（会当做只有一个长度的集合处理），如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sin(@Nullable String column, @Nullable Object values) {
		if (column == null || values == null) return null;
		return new Param(column, values, IN_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sin(@Nullable String column, @Nullable Collection<?> values) {
		if (column == null || values == null || values.isEmpty()) return null;
		return new Param(column, values, IN_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param snotIn(@Nullable String column, @Nullable Object[] values) {
		if (column == null || values == null || values.length == 0) return null;
		return new Param(column, values, NI_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，可以是数组，集合，或一个对象（会当做只有一个长度的集合处理），如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param snotIn(@Nullable String column, @Nullable Object values) {
		if (column == null || values == null) return null;
		return new Param(column, values, NI_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个NOT IN判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param snotIn(@Nullable String column, @Nullable Collection<?> values) {
		if (column == null || values == null || values.isEmpty()) return null;
		return new Param(column, values, NI_STR, Param.INT_NOTIN);
	}
	
	/**
	 * 获取一个LIKE判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值(%：匹配0个或多个值，_:匹配任意一个值)，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param slike(@Nullable String column, @Nullable String value) {
		if (column == null || value == null) return null;
		return new Param(column, value, LIKE_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个NOT LIKE判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值(%：匹配0个或多个值，_:匹配任意一个值)，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param snotLike(@Nullable String column, @Nullable String value) {
		if (column == null || value == null) return null;
		return new Param(column, value, NOT_LIKE_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个IS NULL判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sisNull(@Nullable String column) {
		if (column == null) return null;
		return new Param(column, IS_NULL_STR, Param.SIMPLE_OPERATOR);
	}
	
	/**
	 * 获取一个IS NOT NULL判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sisNotNull(@Nullable String column) {
		if (column == null) return null;
		return new Param(column, IS_NOT_NULL_STR, Param.SIMPLE_OPERATOR);
	}
	
	/**
	 * 获取一个小于{@code <}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param slt(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, LT_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个小于等于{@code <=}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sle(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, LE_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个大于{@code >}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sgt(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, GT_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个大于等于{@code >=}判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param values 要进行匹配的值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 */
	@Nullable
	public static Param sge(@Nullable String column, @Nullable Object value) {
		if (column == null || value == null) return null;
		return new Param(column, value, GE_STR, Param.BINARY_OPERATOR);
	}
	
	/**
	 * 获取一个BETWEEN AND判断规则
	 * 
	 * @param column 判断的列，如果为null则什么都不做
	 * @param start 范围起始值，如果为null则什么都不做
	 * @param end 范围结束值，如果为null则什么都不做
	 * @return 返回Param类，如果无法创建有效的Param类对象，则返回nul
	 * @param <T> 泛型的目的保证start和end数据类型一致
	 */
	@Nullable
	public static <T extends Serializable> Param sbetweenAnd(@Nullable String column, @Nullable T start, @Nullable T end) {
		if (column == null || start == null || end == null) return null;
		BetweenAndQuery<T> value = new BetweenAndQuery<>(start, end);
		return new Param(column, value, null, Param.BETWEEN_AND);
	}

	/**
	 * 取得本条件组内部的连接符号
	 * 
	 * @return and或or
	 */
	public String getInnerOp() {
		return this.innerOp;
	}

	/**
	 * 取得本条件和上一个条件组之间的连接符号，如果此条件组是首个，则为null.
	 * 
	 * @return and或or，如果为首个条件组则返回null
	 */
	public String getOuterOp() {
		return this.outerOp;
	}

	/**
	 * 取得当前条件组中的所有条件参数集合
	 * @return {@link Param} 类对象集合，如果没有，则集合长度为0
	 */
	protected List<Param> getParams() {
		return this.params;
	}

	/**
	 * 自定义完整排序条件，即order by语句.
	 * <p>设置示例：
	 * <ul>
	 * <li><strong>create_time desc</strong></li>
	 * <li><strong>create_time ,update_time desc</strong></li>
	 * <li><strong>create_time desc,update_time asc</strong></li>
	 * </ul>
	 * @param orderBy 要设置的排序条件
	 */
	public SqlParam orderBy(String orderBy){
		this.orderBy = orderBy;
		return this ;
	}
	
	/**
	 * 设置1个或多个使用desc进行排序的字段.
	 * <p>设置示例：
	 * <ul>
	 * <li><strong>create_time</strong></li>
	 * <li><strong>create_time ,update_time </strong></li>
	 * </ul>
	 * <p>如果想要更加灵活的设置order by语句，可以使用{@link #orderBy(String)方法}
	 * @param orderBy 要进行desc排序的字段信息
	 */
	public SqlParam orderByDesc(String orderByCols){
		this.orderBy = orderByCols + " DESC";
		return this ;
	}
	
	/**
	 * 设置1个或多个使用asc进行排序的字段.
	 * <p>设置示例：
	 * <ul>
	 * <li><strong>create_time</strong></li>
	 * <li><strong>create_time ,update_time </strong></li>
	 * </ul>
	 * <p>如果想要更加灵活的设置order by语句，可以使用{@link #orderBy(String)方法}
	 * @param orderBy 要进行asc排序的字段信息
	 */
	public SqlParam orderByAsc(String orderByCols){
		this.orderBy = orderByCols + " ASC";
		return this ;
	}
	
	/**
	 * 获取排序条件
	 * @return 如果有排序条件，则返回，否则返回null。
	 * <br>返回示例：<code>CREATETIME DESC</code> 
	 */
	@Nullable
	public String getOrderBy() {
		return this.orderBy;
	}
	
	@Override
	public String toString() {
		return "SqlParam [params=" + params + ", next=" + next + ", innerOp=" + innerOp + ", outerOp=" + outerOp + "]";
	}
	
	/**
	 * 基于list存储的无key但是拥有map接口的集合.
	 * 
	 * @author Ghwolf
	 */
	class ListParamMap extends AbstractMap<String, Object> {

		private final List<Object> params;
		
		ListParamMap(List<Object> params){
			this.params = params;
		}
		
		@Override
		public Object put(String key, Object value) {
			params.add(value);
			return value ;
		}

		@Override
		public void putAll(Map<? extends String, ? extends Object> m) {
			params.addAll(m.values());
		}

		@Override
		public Object putIfAbsent(String key, Object value) {
			throw new UnsupportedOperationException();
		}

		@Override
		public Set<java.util.Map.Entry<String, Object>> entrySet() {
			return Collections.emptySet();
		}

	}
	
}

